package com.founder.devwork.config;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import java.util.Collection;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
@RequiredArgsConstructor
@Slf4j
public class ServiceMethodValidationAspect {

    private final Validator validator;

    /**
     * 验证服务Save方法的参数是否符合要求
     *
     * 如果Impl类重写save方法，才进行校验
     *
     * @param entity    实体对象
     */
    @Before("execution(* com.founder.devwork.service.impl.*ServiceImpl.save*(..)) && args(entity)")
    public void validatesServiceSaveMethodWithEntityParameter(JoinPoint joinPoint, Object entity) {
        validateEntity(entity);
    }

    /**
     * 验证服务Update方法的参数是否符合要求
     *
     * 如果Impl类重写update方法，才进行校验
     *
     * @param entity    实体对象
     */
    @Before("execution(* com.founder.devwork.service.impl.*ServiceImpl.update*(..)) && args(entity)")
    public void validatesServiceUpdateMethodWithEntityParameter(JoinPoint joinPoint, Object entity) {
        validateEntity(entity);
    }

    /**
     * 验证服务SaveBatch方法的参数是否符合要求
     *
     * 如果Impl类重写saveBatch方法，才进行校验
     *
     * @param collection    集合对象
     */
    @Before("execution(* com.founder.devwork.service.impl.*ServiceImpl.saveBatch*(..)) && args(collection)")
    public void validateServiceSaveBatchMethodWithCollectionParameter(JoinPoint joinPoint, Collection<?> collection) {
        validateCollection(collection);
    }

    /**
     * 验证服务UpdateBatch方法的参数是否符合要求
     *
     * 如果Impl类重写updateBatch方法，才进行校验
     *
     * @param collection    集合对象
     */
    @Before("execution(* com.founder.devwork.service.impl.*ServiceImpl.updateBatch*(..)) && args(collection)")
    public void validateServiceUpdateBatchMethodWithCollectionParameter(JoinPoint joinPoint, Collection<?> collection) {
        validateCollection(collection);
    }

    /**
     * 检查类或字段是否具有约束注解
     * 这里只做简单判断：如果实体非空且其类上有任何校验注解（如@Valid、@NotNull等），则进行校验
     * @param clazz 类
     * @return 是否具有约束注解
     */
    private boolean hasConstraintAnnotation(Class<?> clazz) {
        boolean hasConstraintAnnotation = false;
        // 检查类级别注解
        for (var annotation : clazz.getClass().getAnnotations()) {
            String annName = annotation.annotationType().getName();
            if (annName.startsWith("jakarta.validation.constraints.") || annName.equals("jakarta.validation.Valid")) {
                hasConstraintAnnotation = true;
                break;
            }
        }
        // 检查字段级别注解
        if (!hasConstraintAnnotation) {
            for (var field : clazz.getDeclaredFields()) {
                for (var annotation : field.getAnnotations()) {
                    String annName = annotation.annotationType().getName();
                    if (annName.startsWith("jakarta.validation.constraints.") || annName.equals("jakarta.validation.Valid")) {
                        hasConstraintAnnotation = true;
                        break;
                    }
                }
                if (hasConstraintAnnotation) break;
            }
        }
        return hasConstraintAnnotation;
    }

    /**
     * 验证实体
     *
     * @param entity    实体对象
     */
    private void validateEntity(Object entity) {
        if (entity == null || !hasConstraintAnnotation(entity.getClass())) {
            return;
        }

        // 执行校验
        Set<ConstraintViolation<Object>> violations = validator.validate(entity);
        if (!violations.isEmpty()) {
            // 如果校验失败，则抛出异常，错误信息由统一异常处理类处理
            throw new ConstraintViolationException(violations);
        }
    }

    /**
     * 验证集合
     *
     * @param collection    集合对象
     */
    private void validateCollection(Collection<?> collection) {
        if (collection == null || collection.isEmpty()) {
            return;
        }
        // 检查集合中的元素是否需要校验，如果不需要校验，则不进行校验
        for (Object obj : collection) {
            if (obj != null) {
                if (!hasConstraintAnnotation(obj.getClass())) {
                    return;
                }
                break;
            }
        }

        for (var entity : collection) {
            validateEntity(entity);
        }
    }
}
